// ArchWindow.cpp
// by Charles Mc Auley
// "Programming AutoCAD 2000 with ObjectARX"


#include <acdb.h>		// acdb definitions
#include <adslib.h>		// ads defs
#include <dbsymtb.h>
#include <dbents.h>
#include <gepnt2d.h>
#include <gept2dar.h>
#include <gepnt3d.h>
#include <gearc2d.h>
#include <geoffc2d.h>
#include <geline2d.h>
#include <getol.h>

#include "RectWindow.h"
#include "ArchWindow.h"

ArchWindow::ArchWindow()
{
}

ArchWindow::~ArchWindow()
{
}

void ArchWindow::drawWindow(AcDbBlockTableRecord* pBlkTableRecord)
{

	// Call the base class to draw the
	// rectangular part of the window
	RectWindow::drawWindow(pBlkTableRecord);
	if(!drawArch(pBlkTableRecord))
	{
		ads_printf("\nError drawing arch. ");
		return;
	}
}

Adesk::Boolean ArchWindow::drawArch(AcDbBlockTableRecord* pBlkTableRecord)
{
	AcGePoint2d sp, tp, ep, cp, llPt;
	AcGeVector2d vec;
	AcGePoint2dArray arcPtAr;
	double windLen, windHt, frameThk, smlRad;

	windLen		= getWindowLength();
	windHt		= getWindowHeight();
	llPt		= getWindowStartPoint();
	frameThk	= getRectFrameThk();

	// Calculate the start point, top point
	// and end point of the arc.
	vec.set(0, windHt);
	sp = llPt + vec;

	vec.set(windLen, 0);
	ep = sp + vec;

	vec.set((windLen / 2), (windLen / 2));
	tp = sp + vec;

	AcGeCircArc2d outrGeArc(sp, tp, ep);

	if(!drawArc(pBlkTableRecord, outrGeArc))
	{
		return Adesk::kFalse;
	}

	// Now draw the inner arc
	// Move sp, tp and ep to the inner
	// arc point
	vec.set(frameThk, 0);
	sp += vec;
	ep -= vec;
	vec.set(0, frameThk);
	tp -= vec;

	AcGeCircArc2d inrGeArc(sp, tp, ep);

	if(!drawArc(pBlkTableRecord, inrGeArc))
	{
		return Adesk::kFalse;
	}

	// now draw the small arc and make its radius
	// 1/10 th. of the windLen
	smlRad = windLen / 10;
	cp = inrGeArc.center();
	vec.set(smlRad, 0);
	sp = cp - vec;
	ep = cp + vec;
	vec.set(0, smlRad);
	tp = cp + vec;

	AcGeCircArc2d smlGeArc(sp, tp, ep);

	if(!drawArc(pBlkTableRecord, smlGeArc))
	{
		return Adesk::kFalse;
	}

	// Get 5 sample point along the inrGeArc
	inrGeArc.getSamplePoints(5, arcPtAr);
	if(!drawArchInternalBars(pBlkTableRecord, arcPtAr, cp, inrGeArc, smlGeArc))
	{
		return Adesk::kFalse;
	}

	return Adesk::kTrue;
}

Adesk::Boolean ArchWindow::drawArc(AcDbBlockTableRecord* pBlkTableRecord, AcGeCircArc2d geArc)
{
	AcDbArc *pArc;
	AcDbObjectId arcId;
	Acad::ErrorStatus es;

	AcGePoint2d sp, cp, ep;
	AcGePoint3d cenPt;

	double sang, eang, rad;

	sp = geArc.startPoint();
	ep = geArc.endPoint();
	cp = geArc.center();
	rad = geArc.radius();
	sang = geArc.startAng();
	eang = geArc.endAng();

	cenPt.set(cp.x, cp.y, 0.0);
	
	pArc = new AcDbArc(cenPt, rad, sang, eang);
	es = pBlkTableRecord->appendAcDbEntity(arcId, pArc);
	if(es != Acad::eOk)
	{
		if(pArc != NULL)
		{
			delete pArc;
		}

		return Adesk::kFalse;
	}

	pArc->close();

	return Adesk::kTrue;
}

Adesk::Boolean ArchWindow::drawArchInternalBars(AcDbBlockTableRecord *pBlkTableRecord,
												AcGePoint2dArray arcPtAr,
												AcGePoint2d cp,
												AcGeCircArc2d inrGeArc,
												AcGeCircArc2d smlGeArc)
{
	AcDbLine *pLinEnt;
	AcDbObjectId linEntId;
	AcGeLine2d cenLine, offLine1, offLine2;
	AcGePoint2d sp, ep, startPt1, endPt1, startPt2, endPt2;
	AcGePoint3d startPt3d2, endPt3d1;
	AcGePoint2dArray offCurv1Ar, offCurv2Ar;
	AcGeTol tol;
	double inrFrmThk;
	int intn;

	inrFrmThk = getIntrFrameThk();

	sp = cp;

	for(int count = 1; count < (arcPtAr.length() - 1); count++)
	{
		ep = arcPtAr.at(count);
		cenLine.set(sp, ep);
		AcGeOffsetCurve2d offCurv1(cenLine,  (inrFrmThk / 2));
		AcGeOffsetCurve2d offCurv2(cenLine, -(inrFrmThk / 2));
		offCurv1.getSamplePoints(2, offCurv1Ar);
		offCurv2.getSamplePoints(2, offCurv2Ar);

		offLine1.set(offCurv1Ar.at(0), offCurv1Ar.at(1));
		offLine2.set(offCurv2Ar.at(0), offCurv2Ar.at(1));

		inrGeArc.intersectWith(offLine1, intn, endPt1, startPt1, tol);
		smlGeArc.intersectWith(offLine1, intn, startPt2, endPt2, tol);

		startPt3d2.set(startPt2.x, startPt2.y, 0.0);
		endPt3d1.set(endPt1.x, endPt1.y, 0.00);

		pLinEnt = new AcDbLine(startPt3d2, endPt3d1);
		pBlkTableRecord->appendAcDbEntity(linEntId, pLinEnt);
		pLinEnt->close();

		inrGeArc.intersectWith(offLine2, intn, endPt1, startPt1, tol);
		smlGeArc.intersectWith(offLine2, intn, startPt2, endPt2, tol);

		offLine1.set(offCurv1Ar.at(0), offCurv1Ar.at(1));
		offLine2.set(offCurv2Ar.at(0), offCurv2Ar.at(1));

		startPt3d2.set(startPt2.x, startPt2.y, 0.0);
		endPt3d1.set(endPt1.x, endPt1.y, 0.00);

		pLinEnt = new AcDbLine(startPt3d2, endPt3d1);
		pBlkTableRecord->appendAcDbEntity(linEntId, pLinEnt);
		pLinEnt->close();
		
	}// for


	return Adesk::kTrue;
}

void ArchWindow::setWindowHeight(double windHeight)
{
	double windLen = getWindowLength();
	rectFrameHt = windHeight - (windLen / 2);
	RectWindow::setWindowHeight(rectFrameHt);
}